#include "py/builtin.h"
#include "py/runtime.h"
#include "py/obj.h"
#include "py/binary.h"
#include "moopi.h"
#include <string.h>

STATIC mp_obj_t moopi_object_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
{
    // 创建对象
    moopi_object_t *self = (moopi_object_t *)m_new_obj(moopi_object_t);
    // 设置对象实例类型
    self->base.type = &moopi_type_object;
    self->bool_val = true;
    self->byte_val = 0x55;
    self->dict = mp_obj_new_dict(0);
    self->iter_index = 0;
    // 返回对象
    return MP_OBJ_FROM_PTR(self);
}

/**
 * @brief 析构函数
*/
STATIC mp_obj_t moopi_object_destructor(mp_obj_t self_in){
    printf("析构函数被调用\n");
    moopi_object_t *self = MP_OBJ_TO_PTR(self_in);
    m_del_obj(self->base.type,self);
    
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(moopi_object_destructor_obj, moopi_object_destructor);

/**
 * @brief 函数实例的方法
 * 第一个参数永远是实例自身
*/
STATIC mp_obj_t moopi_object_size(size_t n_args, const mp_obj_t *args){
    moopi_object_t *self = MP_OBJ_TO_PTR(args[0]);
    if(n_args==2){
        self->width = self->height = mp_obj_get_int(args[1]);
    }else if(n_args==3){
        self->width = mp_obj_get_int(args[1]);
        self->height = mp_obj_get_int(args[2]);
    }else{
        mp_obj_t res[2]={
            mp_obj_new_int(self->width),
            mp_obj_new_int(self->height)
        };
        // 如果是查询，则返回元祖
        return MP_OBJ_FROM_PTR(mp_obj_new_tuple(2,res));
    }
    // 返回本实例，可以做链式操作
    return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(moopi_object_size_obj, 1, 3, moopi_object_size);

STATIC mp_obj_t moopi_object_location(size_t n_args, const mp_obj_t *args){
    moopi_object_t *self = MP_OBJ_TO_PTR(args[0]);
    if(n_args==2){
        self->x = self->y = mp_obj_get_int(args[1]);
    }else if(n_args==3){
        self->x = mp_obj_get_int(args[1]);
        self->y = mp_obj_get_int(args[2]);
    }else{
        mp_obj_t res[2]={
            mp_obj_new_int(self->x),
            mp_obj_new_int(self->y)
        };
        return MP_OBJ_FROM_PTR(mp_obj_new_tuple(2,res));
    }
    return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(moopi_object_location_obj, 1, 3, moopi_object_location);

/**
 * @brief 静态方法测试函数
*/
STATIC mp_obj_t moopi_object_new(){
    moopi_object_t *self = (moopi_object_t *)m_new_obj(moopi_object_t);
    self->base.type = &moopi_type_object;
    return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_FUN_OBJ_0(moopi_object_new_obj, moopi_object_new);

/**
 * @brief 打印函数
*/
STATIC void moopi_object_print(const mp_print_t *print, const mp_obj_t self_in, mp_print_kind_t kind)
{
    moopi_object_t *self = MP_OBJ_TO_PTR(self_in);
    if(self!=MP_OBJ_NULL){
        const char *type = mp_obj_get_type_str(self_in);
        mp_printf(print, "<MooPi:%s>(x:%d, y:%d, width:%d, height:%d, byte_val:0x%02X)", type, self->x, self->y, self->width, self->height,self->byte_val);
    }else{
        mp_printf(print, "<MooPi:Object>(null object)");
    }
}

/**
 * @brief 直接调用函数
*/
STATIC mp_obj_t moopi_object_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args)
{
    printf("Called moopi_object_call\n");
    return mp_const_none;
}

/**
 * @brief 属性a函数
*/
STATIC void moopi_object_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest){
    const mp_obj_type_t *type = mp_obj_get_type(self_in);
    mp_map_t *locals_map = &type->locals_dict->map;
    mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
    if (elem != NULL)
    {
        mp_convert_member_lookup(self_in, type, elem->value, dest);
    }

    moopi_object_t *self = MP_OBJ_TO_PTR(self_in);
    switch (attr)
    {
    case MP_QSTR_width :
        if(dest[0] == MP_OBJ_SENTINEL){
            self->width = mp_obj_get_int(dest[1]);
            dest[0] = MP_OBJ_NULL;
        }else{
            dest[0] = mp_obj_new_int(self->width);
        }
        break;
    case MP_QSTR_height :
        if(dest[0] == MP_OBJ_SENTINEL){
            self->height = mp_obj_get_int(dest[1]);
            dest[0] = MP_OBJ_NULL;
        }else{
            dest[0] = mp_obj_new_int(self->height);
        }
        break;
    case MP_QSTR_x :
        if(dest[0] == MP_OBJ_SENTINEL){
            self->x = mp_obj_get_int(dest[1]);
            dest[0] = MP_OBJ_NULL;
        }else{
            dest[0] = mp_obj_new_int(self->x);
        }
        
        break;
    case MP_QSTR_y :
        if(dest[0] == MP_OBJ_SENTINEL){
            self->y = mp_obj_get_int(dest[1]);
            dest[0] = MP_OBJ_NULL;
        }else{
            dest[0] = mp_obj_new_int(self->y);        
        }
        break;
    default:
        break;
    }
}

/**
 * @brief 一元运算符
*/
STATIC mp_obj_t moopi_object_unary(mp_unary_op_t op, mp_obj_t self_in){
    moopi_object_t *self = MP_OBJ_TO_PTR(self_in);
    switch (op)
    {
    case MP_UNARY_OP_POSITIVE:  // +
        return MP_OBJ_FROM_PTR(mp_obj_new_int(self->x));
    case MP_UNARY_OP_NEGATIVE:  // -
        return MP_OBJ_FROM_PTR(mp_obj_new_int(-self->x));
    case MP_UNARY_OP_INVERT:    // ~
        return MP_OBJ_FROM_PTR(mp_obj_new_int(~self->byte_val));
    case MP_UNARY_OP_NOT:       // not
        return MP_OBJ_FROM_PTR(mp_obj_new_bool(!self->bool_val));
    case MP_UNARY_OP_BOOL:      // if(obj)
        return mp_obj_new_bool(self->bool_val);
    case MP_UNARY_OP_LEN:       // len()
        return MP_OBJ_NEW_SMALL_INT(self->dict->map.alloc-1);
    case MP_UNARY_OP_HASH:      // hash()
        return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash((const byte *)"12345",5));
    case MP_UNARY_OP_ABS:       // abs()
        return MP_OBJ_FROM_PTR(mp_obj_new_int(self->x));
    case MP_UNARY_OP_INT:       // int()
        return MP_OBJ_NEW_SMALL_INT(self->x);
    case MP_UNARY_OP_SIZEOF:    // sizeof()
        return MP_OBJ_FROM_PTR(sizeof(*self));
    }
    return mp_const_none;
}

/**
 * @brief 二元运算符
*/
STATIC mp_obj_t moopi_object_binary(mp_binary_op_t op, mp_obj_t self_in, mp_obj_t value){
    moopi_object_t *self = (moopi_object_t *)MP_OBJ_TO_PTR(self_in);
    
    switch (op)
    {
    case MP_BINARY_OP_LESS : // <
        {
            int32_t val = mp_obj_get_int(value);
            return MP_OBJ_FROM_PTR(mp_obj_new_bool(self->x<val));
        }
        break;
    case MP_BINARY_OP_INPLACE_OR : // |=
        {
            uint8_t val = mp_obj_get_int(value);
            self->byte_val |= val;
            return MP_OBJ_FROM_PTR(self);
        }
        break;
    case MP_BINARY_OP_OR : // |
        {
            uint8_t val = mp_obj_get_int(value);
            return MP_OBJ_FROM_PTR(mp_obj_new_int(self->byte_val | val));
        }
        break;
    default:
        break;
    }
    return mp_const_none;
}

/**
 * @brief 下标函数
*/
STATIC mp_obj_t moopi_object_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
    moopi_object_t *self = (moopi_object_t *)MP_OBJ_TO_PTR(self_in);

    if (value !=MP_OBJ_SENTINEL)
    {
        mp_obj_dict_store(self->dict,index,value);
    }
    
    mp_map_t *map = mp_obj_dict_get_map(self->dict);
    if(mp_map_lookup(map,index,MP_MAP_LOOKUP)!=NULL){
        return mp_obj_dict_get(self->dict,index);
    }
    return mp_const_none;
}

/**
 * @brief 迭代器获取函数
*/
STATIC mp_obj_t moopi_object_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf){
    moopi_object_t *self = (moopi_object_t *)MP_OBJ_TO_PTR(self_in);
    self->iter_index = 0;
    return self_in;
}
/**
 * @brief 迭代器下一个元素
*/
STATIC mp_obj_t moopi_object_iternext(mp_obj_t self_in){
    moopi_object_t *self = (moopi_object_t *)MP_OBJ_TO_PTR(self_in);
    mp_map_t *map = mp_obj_dict_get_map(self->dict);
    mp_map_elem_t *elem = NULL;
    do{
        if(self->iter_index<map->alloc){
            elem = map->table+self->iter_index;
        }else{
            // 迭代结束返回这个值
            return MP_OBJ_STOP_ITERATION;
        }
        
        self->iter_index++;
    }while(elem->key == MP_OBJ_NULL && elem->key == MP_OBJ_NULL);   // 跳过空值
    mp_obj_t res[2]={elem->key,elem->value};
    return MP_OBJ_FROM_PTR(mp_obj_new_tuple(2,res)); 
}

// 定义类成员的全局字典
const mp_rom_map_elem_t moopi_object_local_dict_table[] = {
    {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&moopi_object_destructor_obj)},
    {MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&moopi_object_new_obj)},
    {MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&moopi_object_size_obj)},
    {MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&moopi_object_location_obj)},
};

// 将成员全局字典转换为 micropython 对象
STATIC MP_DEFINE_CONST_DICT(moopi_object_local_dict, moopi_object_local_dict_table);

// 定义类的类型结构
const mp_obj_type_t moopi_type_object = {
    {&mp_type_type},
    .name = MP_QSTR_Object,
    .locals_dict = (mp_obj_dict_t *)&moopi_object_local_dict,
    .make_new = moopi_object_make_new,
    .print = moopi_object_print,
    .call = moopi_object_call,
    .attr = moopi_object_attr,
    .unary_op = moopi_object_unary,
    .binary_op = moopi_object_binary,
    .subscr = moopi_object_subscr,
    .getiter = moopi_object_getiter,
    .iternext = moopi_object_iternext,
};